home *** CD-ROM | disk | FTP | other *** search
- /*
- >> BitMapRgn.c, June 90 <<
- >> <<
- >> Nigel Perry, np@doc.ic.ac.uk <<
- >> Dept of Computing, Imperial College, 180 Queens Gate, <<
- >> London SW7 2BZ, England <<
- >> <<
- >> Version of the BitMapRgn trap (0xA8D7) which is not in all systems <<
- >> This C/asm version is an extension of a C routine written <<
- >> by Juri Munkki in April 89. Added error checks, now works with a <<
- >> BitMap with any origin, used assembler for speed <<
- >> <<
- >> Juri Munkki, jmunkki@kampi.hut.fi <<
- >> Helsinki University of Technology Computing Centre <<
- >> Otakaari 1 U044B, SF02150 Espoo, Finland <<
- >> <<
- >> This program is in the PUBLIC DOMAIN. <<
- */
-
- /* Define TRAPATCH if trap patch version (project BMTR Trap π).
- Will compile a TRAP resource and write it to BMTR XCMD π.rsrc,
- to use in the BMTR Patcher.π & BMTR Init.π this TRAP resource must be
- copied with ResEdit to the appropriate π.rsrc file. DO NOT change this
- project to write directly to another π.rsrc file, they contain other
- resources which you will DESTROY.
- */
- #define TRAPATCH
-
- #include <asm.h>
- #define _BitMapToRegion 0xA8D7
- #define _Unimplemented 0xA89F
-
- #define rgnTooBigErr -500
-
- #ifdef TRAPATCH
- #define BitMapRgn main
- /* CODE header */
- header()
- { extern pascal OSErr BitMapRgn();
-
- asm
- { bra.s @1 ; header
- dc.b 'n','p','9','0' ; header + 2
- dc.b 'j','u','r','i' ; header + 6
- @1: jmp BitMapRgn
- }
- }
- #endif TRAPATCH
-
- /*
- >> Convert a bitmap into a region.
- */
- pascal OSErr BitMapRgn(RgnHandle, BitMap *);
- pascal OSErr BitMapRgn(Target, Bits)
- RgnHandle Target;
- BitMap *Bits;
- { int *TargetBase; /* StripAddress(*Target) */
- int *RowStart; /* Index of first x value on row */
- int TargetSize,RgnSize; /* Size in data words & bytes */
- Rect TempRect,RgnBounds; /* Temporary & region bounds rects */
- BitMap RowBitMap; /* Working bitmap with one row in it */
- int i; /* Row counter in a "for" loop */
- int diff;
- int left;
- /* three address registers a2-4 */
- register int *TargetP; /* Pointer to region data array */
- register int *MaxTarget; /* Memory management stuff */
- #ifndef TRAPATCH
- register long *BitP; /* Pointer to current line */
- #else
- /* need to force a4 in LSC CODE resource */
- #define BitP a4
- #endif
- /* five data registers d3-7 */
- register int shiftcount; /* shift count for BitWord */
- register long BitWord; /* current 32 bits of line */
- register int x; /* Column counter in a "for" loop */
- register int pixelstatus; /* Flag is false if last pixel is white */
- register int right;
-
- #ifdef TRAPATCH
- /* save a4 in patch */
- asm
- { move.l a4,-(a7)
- }
- #endif
- asm
- { move.l #4096,d0 /* Initial guess for final region size */
- move.w d0,TargetSize
- move.l Target,a0 /* Allocate initial data buffer */
- _SetHandleSize
- bne @bomb /* Did we run out of RAM? 0=failure. */
- _HLock /* HLock((Handle)Target); */
-
- /* TargetP points to region data */
- move.l Target,a0 /* TargetBase = StripAddres(*(Handle)Target) */
- move.l (a0),d0
- _StripAddress
- move.l d0,a0
- move.l d0,TargetBase
- lea 10(a0),TargetP /* TargetP = (TargetBase + 10); */
- /* A safe maximum value for our index */
- move.w TargetSize,d0
- lea -8(a0,d0.w),MaxTarget /* MaxTarget = TargetBase + TargetSize - 8; */
-
- /* Set region bounds to nothing: */
- move.l #0x7FFF7FFF,RgnBounds.top /* SetRect(&RgnBounds,32767,32767,-32767,-32767); */
- move.l #0x80018001,RgnBounds.bottom
-
- /* Set up a bitmap with a single line: */
- move.l Bits,a0
- move.w OFFSET(BitMap,bounds)+OFFSET(Rect,left)(a0),TempRect.left /* Set up left & right bounds */
- move.w OFFSET(BitMap,bounds)+OFFSET(Rect,right)(a0),TempRect.right
- move.w OFFSET(BitMap,bounds)+OFFSET(Rect,top)(a0),d0
- move.w d0,TempRect.top; /* Single row bitmap with height = 1 */
- addq.w #1,d0
- move.w d0,TempRect.bottom
- move.l TempRect.top,RowBitMap.bounds.top /* RowBitMap.bounds=TempRect; */
- move.l TempRect.bottom,RowBitMap.bounds.bottom;
- moveq #15,d0 /* RowBitMap.rowBytes = ((TempRect.width + 15) >> 4) << 1; */
- add.w TempRect.right,d0
- sub.w TempRect.left,d0
- asr.w #4,d0
- asl.w #1,d0
- move.w d0,RowBitMap.rowBytes
- ext.w d0 /* RowBitMap.baseAddr = NewPtr(RowBitMap.rowBytes); */
- _NewPtr
- bne @bomb
- move.l a0,RowBitMap.baseAddr
- }
-
- /* Start out with the first line of the source bitmap */
- CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcCopy,0);
-
- asm
- { /* right = Bits->bounds.right; */
- move.l Bits,a0
- move.w OFFSET(BitMap,bounds)+OFFSET(Rect,right)(a0),right
- move.w OFFSET(BitMap,bounds)+OFFSET(Rect,left)(a0),left
- /* i = Bits->bounds.bottom - Bits->bounds.top; */
- move.w OFFSET(BitMap,bounds)+OFFSET(Rect,bottom)(a0),d0
- sub.w OFFSET(BitMap,bounds)+OFFSET(Rect,top)(a0),d0
- move.w d0,i
- }
-
- for(; i >= 0; i--) /* For every line and more */
- { /* Row data starts with Y value*/
- asm
- { move.w TempRect.top,(TargetP)+ /* *TargetP++ = TempRect.top; */
- }
- RowStart = TargetP; /* X values on row start here */
- pixelstatus = 0; /* Pixels outside bitmap are white */
-
- asm
- { move.l RowBitMap.baseAddr,BitP /* BitP = (long *)RowBitMap.baseAddr; */
- }
- shiftcount = 0;
- for(x = left; x<right; x++)
- { asm
- { tst.w shiftcount
- bne.s @nextBit
- moveq #32,shiftcount
- move.l (BitP)+,BitWord /* BitWord = *BitP++; */
- @nextBit
- subq.w #1,shiftcount
- /* Test for a change */
- /* if((BitTst(RowBitMap.baseAddr,x)!=0) != pixelstatus) */
- lsl.l #1,BitWord
- scs d0
- eor.b pixelstatus,d0
- beq @elselab
- }
- { asm
- { /* Color changed */
- not.b pixelstatus /* pixelstatus = !pixelstatus; */
- /* Record x coordinate */
- move.w x,(TargetP)+ /* *TargetP++ = x; */
- }
- if(TargetP >= MaxTarget) /* Is the buffer full? */
- { asm
- { move.l TargetP,d0 /* diff = TargetP - TargetBase; */
- sub.l TargetBase,d0
- move.w d0,diff
- add.w #2048,TargetSize /* Enlarge the buffer */
- bvc.s @sizeOk /* if((TargetSize+=2048) > 32767) */
- move.w #rgnTooBigErr,d0
- bra @bomb2
- @sizeOk
- move.l Target,a0 /* Unlock to change size */
- _HUnlock
- move.w TargetSize,d0 /* Change the size */
- ext.l d0
- _SetHandleSize
- bne @bomb2 /* No success? */
- _HLock /* Lock it again */
-
- move.l Target,a0 /* TargetBase = StripAddress(*(Handle)Target); */
- move.l (a0),d0
- _StripAddress
- move.l d0,TargetBase
- move.l d0,TargetP
- adda.w diff,TargetP /* TargetP = TargetBase + diff; */
- /* New maximum index */
- subq.l #8,d0
- move.l d0,MaxTarget /* MaxTarget= TargetBase + TargetSize; */
- adda.w TargetSize,MaxTarget
- }
- }
- }
- elselab:
- ;
- }
- if(pixelstatus) /* Last pixel was black, record edge */
- asm
- { move.w x,(TargetP)+ /* *TargetP++=x; */
- }
- if(RowStart==TargetP) /* Row was empty (no changes) */
- TargetP--; /* Remove Y value from data */
- else
- { /* Check for new region bounds: */
- asm
- { move.l RowStart,a0 /* if(*RowStart < RgnBounds.left) */
- move.w (a0),d0
- cmp.w RgnBounds.left,d0
- bge.s @else1
- move.w d0,RgnBounds.left /* RgnBounds.left = *RowStart; */
- @else1
- move.w -2(TargetP),d0 /* if(TargetP[-1] > RgnBounds.right) */
- cmp.w RgnBounds.right,d0
- ble.s @else2
- move.w d0,RgnBounds.right /* RgnBounds.right = TargetP[-1]; */
- @else2
- }
-
- RgnBounds.bottom = TempRect.top;
-
- /* Write an "end of line" flag */
- asm
- { move.w #32767,(TargetP)+ /* *TargetP++ = 32767; */
- }
- }
-
- /* Copy current line into the single line bitmap: */
- if(i>0) CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcCopy,0);
-
- TempRect.top++; TempRect.bottom++; /* Move one line down */
-
- /* If we are still inside the bitmap, XOR this line with the previous line:*/
- if(i>1) CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcXor,0);
- }
-
- /* RgnBounds.top = TargetBase[5]; */ /* Top boundary is first recorded Y coordinate */
- asm
- { move.l TargetBase,a0 ; (*)
- move.w 10(a0),RgnBounds.top
- }
-
- /* If the region is empty, set the bounds rect to an empty rectangle: */
- if(RgnBounds.right<=RgnBounds.left || RgnBounds.bottom<=RgnBounds.top)
- asm
- { clr.l RgnBounds.top /* SetRect(&RgnBounds,0,0,0,0); */
- clr.l RgnBounds.bottom
- }
-
- asm
- { /* Write an "end of region" flag */
- move.w #32767,(TargetP)+ /* *TargetP++ = 32767; */
-
- /* Calculate region size.*/
- move.l TargetP,d0 /* RgnSize = (TargetP - TargetBase) * 2; */
- ; sub.l TargetBase,d0 /* result must be <= 32767 */
- sub.l a0,d0 ; TargetBase is in a0 (*)
- cmp.w #28,d0 /* if(RgnSize<=28) RgnSize=10; */
- bgt.s @3
- moveq #10,d0 /* Rectangular or empty region is only a Rect */
- @3: move.w d0,RgnSize ; (**)
-
- /* Store region bounds rectangle */
- /* ((RgnPtr)TargetBase)->rgnBBox=RgnBounds; */
- ; move.l TargetBase,a0 already in a0 (*)
- move.l RgnBounds.top,OFFSET(Region,rgnBBox)+OFFSET(Rect,top)(a0)
- move.l RgnBounds.bottom,OFFSET(Region,rgnBBox)+OFFSET(Rect,bottom)(a0)
- /* Store region size (low 16 bits) */
- /* ((RgnPtr)TargetBase)->rgnSize=RgnSize; */
- move.w d0,OFFSET(Region,rgnSize)(a0) ; RgnSize is in d0 (**)
- }
-
-
-
- asm
- { /* Unlock our target region. */
- move.l Target,a0 /* HUnlock((Handle)Target); */
- _HUnlock
-
- /* Resize region to optimally small */
- move.w RgnSize,d0
- ext.l d0
- _SetHandleSize /* SetHandleSize((Handle)Target,RgnSize); */
- bne.s @bomb2 /* shouldn't occur... */
- }
-
- asm
- { move.l RowBitMap.baseAddr,a0 /* DisposPtr(RowBitMap.baseAddr) */
- _DisposPtr
- bne.s @bomb
- bra.s @done /* return noErr */
- bomb2:
- move.w d0,-(a7)
- move.l RowBitMap.baseAddr,a0
- _DisposPtr
- bra.s @bomb3
- bomb:
- move.w d0,-(a7)
- bomb3:
- move.l Target,a0
- move.l a0,-(a7)
- _HUnlock /* may still be locked */
- _SetEmptyRgn
- move.w (a7)+,d0
-
- done:
- #ifdef TRAPATCH
- ; get a4 back
- move.l (a7)+,a4
- #endif
-
- }
-
- }